/*
 * Copyright (c) 2003-2009 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package ar.edu.itba.it.cg.grupo01.game.terrain;

import java.net.URL;

import ar.edu.itba.it.cg.grupo01.vehicle.Car;

import com.jme.image.Texture;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.math.spring.SpringPoint;
import com.jme.math.spring.SpringPointForce;
import com.jme.renderer.Renderer;
import com.jme.scene.shape.Cylinder;
import com.jme.scene.state.CullState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;
import com.jmex.effects.cloth.ClothPatch;
import com.jmex.effects.cloth.ClothUtils;

/**
 * Flag maintains the object that is the "goal" of the game. The drivers are to
 * try to grab the flags for points. The main job of the class is to build the
 * flag geometry, and position itself randomly within the level after a period
 * of time.
 * 
 * @author Mark Powell
 * 
 */
public class Flag extends Checkpoint {
	private static final long serialVersionUID = 1L;

	// the cloth that makes up the flag.
	private ClothPatch cloth;
	// parameters for the wind
	private float windStrength = 15f;
	private Vector3f windDirection = new Vector3f(0.8f, 0, 0.2f);
	private SpringPointForce gravity, wind;

	private long points;

	public Flag(String name, URL flagImage, Vector3f pos, long points) {
		super(name, pos);

		this.points = points;
		
		// create a cloth patch that will handle the flag part of our flag.
		cloth = new ClothPatch("cloth", 25, 25, 1f, 10);
		// Add our custom flag wind force to the cloth
		wind = new RandomFlagWindForce(windStrength, windDirection);
		cloth.addForce(wind);
		// Add a simple gravitational force:
		gravity = ClothUtils.createBasicGravity();
		cloth.addForce(gravity);

		// Create the flag pole
		Cylinder c = new Cylinder("pole", 10, 10, 0.5f, 50);
		this.attachChild(c);
		Quaternion q = new Quaternion();
		// rotate the cylinder to be vertical
		q.fromAngleAxis(FastMath.PI / 2, new Vector3f(1, 0, 0));
		c.setLocalRotation(q);
		c.setLocalTranslation(new Vector3f(-12.5f, -12.5f, 0));

		// create a texture that the flag will display.
		// Let's promote jME!
		TextureState ts = DisplaySystem.getDisplaySystem().getRenderer()
				.createTextureState();
		ts.setTexture(TextureManager.loadTexture(flagImage,
				Texture.MinificationFilter.Trilinear,
				Texture.MagnificationFilter.Bilinear));

		cloth.setRenderState(ts);
		// We want to see both sides of the flag, so we will turn back facing
		// culling OFF.
		CullState cs = DisplaySystem.getDisplaySystem().getRenderer()
				.createCullState();
		cs.setCullFace(CullState.Face.None);
		cloth.setRenderState(cs);
		this.attachChild(cloth);

		// We need to attach a few points of the cloth to the poll. These points
		// shouldn't
		// ever move. So, we'll attach five points at the top and 5 at the
		// bottom.
		// to make them not move the mass has to be high enough that no force
		// can move it.
		// I also move the position of these points slightly to help bunch up
		// the flag to
		// give it better realism.
		for (int i = 0; i < 5; i++) {
			cloth.getSystem().getNode(i * 25).position.y *= .8f;
			cloth.getSystem().getNode(i * 25).setMass(Float.POSITIVE_INFINITY);

		}

		for (int i = 24; i > 19; i--) {
			cloth.getSystem().getNode(i * 25).position.y *= .8f;
			cloth.getSystem().getNode(i * 25).setMass(Float.POSITIVE_INFINITY);

		}
		this.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
		this.setLocalScale(0.25f);

	}
	
	@Override
	public long getScore() {
		return points;
	}

	/**
	 * RandomFlagWindForce defines a SpringPointForce that will slighly adjust
	 * the direction of the wind and the force of the wind. This will cause the
	 * flag to flap in the wind and rotate about the flag pole slightly, giving
	 * it a realistic movement.
	 * 
	 * @author Mark Powell
	 * 
	 */
	private class RandomFlagWindForce extends SpringPointForce {

		private final float strength;
		private final Vector3f windDirection;

		/**
		 * Creates a new force with a defined max strength and a starting
		 * direction.
		 * 
		 * @param strength
		 *            the maximum strength of the wind.
		 * @param direction
		 *            the starting direction of the wind.
		 */
		public RandomFlagWindForce(float strength, Vector3f direction) {
			this.strength = strength;
			this.windDirection = direction;
		}

		/**
		 * called during the update of the cloth. Will adjust the direction
		 * slightly and adjust the strength slightly.
		 */
		public void apply(float dt, SpringPoint node) {
			windDirection.x += dt * (FastMath.nextRandomFloat() - 0.5f);
			windDirection.z += dt * (FastMath.nextRandomFloat() - 0.5f);
			windDirection.normalize();
			float tStr = FastMath.nextRandomFloat() * strength;
			node.acceleration.addLocal(windDirection.x * tStr, windDirection.y
					* tStr, windDirection.z * tStr);
		}
	}

}